package org.yan.kangaroo.common.config.feign;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.util.StringUtils;
import org.yan.kangaroo.common.constant.WebRequestHeaderConstants;
import org.yan.kangaroo.common.threadlocal.GlobalRequestIdThreadLocal;

import java.io.IOException;
import java.util.*;

/**
 * @author xian
 * @date 06/27/2019
 */
@Configuration
@Slf4j
public class FeignRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        if (HttpMethod.GET.name().equalsIgnoreCase(requestTemplate.method()) && requestTemplate.requestBody().asBytes() != null) {
            try {
                ObjectMapper objectMapper = new ObjectMapper();
                JsonNode jsonNode = objectMapper.readTree(requestTemplate.requestBody().asBytes());
                Map<String, Collection<String>> queries = new HashMap<>(5);
                buildQuery(jsonNode, "", queries);
                requestTemplate.queries(queries);
            } catch (IOException e) {
                log.error("[apply] build params error:", e);
            }
        }
        String requestId = GlobalRequestIdThreadLocal.getRequestId();
        if (org.apache.commons.lang3.StringUtils.isNoneBlank(requestId)) {
            log.debug("[apply] 设置请求头RequestId:{}", requestId);
            requestTemplate.header(WebRequestHeaderConstants.REQUEST_ID, requestId);
        }
    }

    private void buildQuery(JsonNode jsonNode, String path, Map<String, Collection<String>> queries) {
        if (!jsonNode.isContainerNode()) {
            if (jsonNode.isNull()) {
                return;
            }
            Collection<String> values = queries.computeIfAbsent(path, k -> new ArrayList<>());
            values.add(jsonNode.asText());
            return;
        }
        if (jsonNode.isArray()) {
            Iterator<JsonNode> it = jsonNode.elements();
            while (it.hasNext()) {
                buildQuery(it.next(), path, queries);
            }
        } else {
            Iterator<Map.Entry<String, JsonNode>> it = jsonNode.fields();
            while (it.hasNext()) {
                Map.Entry<String, JsonNode> entry = it.next();
                if (StringUtils.hasText(path)) {
                    buildQuery(entry.getValue(), path + "." + entry.getKey(), queries);
                } else {
                    buildQuery(entry.getValue(), entry.getKey(), queries);
                }
            }
        }
    }
}
